package com.cyc.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

//懒汉式单例  通过反射的newInstance 发现枚举无法通过反射创建！！！！！
public class LazyManReflex {

    //添加标记位
    private static boolean marker = false;
    private LazyManReflex(){
        //解决反射下创建对象  如果都是通过反射去创建对象 还是会被保护 可以通过添加标记位 但是标记位也可以通过反射去设置，依然可以破坏单例
        synchronized (LazyManReflex.class){
//            if (lazyMan!=null){
//                throw new RuntimeException("不要尝试通过反射破坏单例!");
//            }
            if (marker == false){
                marker = true;
            }else {
                throw new RuntimeException("不要尝试通过反射破坏单例!");
            }
        }
        System.out.println(Thread.currentThread().getName() + "OK");
    }
    private volatile static LazyManReflex lazyMan;

    //双重检测锁模式的懒汉式单例 DCL懒汉式
    public static LazyManReflex getInstance(){
        if (lazyMan==null){
            synchronized (LazyManReflex.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyManReflex(); //不是原子性操作 有可能出现指令重排
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //使用反射可以实例不同对象

        //单例模式获取对象
        //LazyManReflex instance = LazyManReflex.getInstance();

        //获取标记位
        Field marker = LazyManReflex.class.getDeclaredField("marker");
        //无视标记私有
        marker.setAccessible(true);

        //通过反射得到无参构造器
        Constructor<LazyManReflex> declaredConstructor = LazyManReflex.class.getDeclaredConstructor(null);
        //无视私有构造器
        declaredConstructor.setAccessible(true);



        //通过反射实例化  都是通过反射创建对象 无法走到第三层锁 即 构造器锁
        LazyManReflex lazyManReflex01 = declaredConstructor.newInstance();
        //第一次反射实例后 再动态改变标记位的值 使得标记位无效
        marker.set(lazyManReflex01,false);

        LazyManReflex lazyManReflex02 = declaredConstructor.newInstance();
        //等到结果不是同个对象  说明 反射会破坏DCL单例懒汉
//        System.out.println(instance==lazyManReflex);
        System.out.println(lazyManReflex01==lazyManReflex02);
    }
}
